package org.dromara.ai.controller;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.ai.domain.dto.AiChatRequest;
import org.dromara.ai.domain.dto.AiChatResponse;
import org.dromara.ai.service.AiChatService;
import org.dromara.common.core.domain.R;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.web.core.BaseController;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * AI聊天控制器
 * 提供AI聊天相关的REST API接口
 *
 * @author RuoYi
 * @since 2024-01-01
 */
@Slf4j
@RestController
@RequestMapping("/ai/chat")
@RequiredArgsConstructor
public class AiChatController extends BaseController {

    private final AiChatService aiChatService;

    /**
     * 同步聊天对话
     *
     * @param request 聊天请求
     * @return 聊天响应
     */
    @PostMapping("/sync")
    @Log(title = "AI聊天", businessType = BusinessType.OTHER)
    public R<AiChatResponse> chat(@Validated @RequestBody AiChatRequest request) {
        log.info("接收到AI聊天请求 - 用户: {}, 模型: {}", request.getUserId(), request.getModel());
        
        try {
            AiChatResponse response = aiChatService.chat(request);
            return R.ok(response);
        } catch (Exception e) {
            log.error("AI聊天失败", e);
            return R.fail("AI聊天失败: " + e.getMessage());
        }
    }

    /**
     * 异步聊天对话
     *
     * @param request 聊天请求
     * @return 异步聊天响应
     */
    @PostMapping("/async")
    @Log(title = "AI异步聊天", businessType = BusinessType.OTHER)
    public R<CompletableFuture<AiChatResponse>> chatAsync(@Validated @RequestBody AiChatRequest request) {
        log.info("接收到AI异步聊天请求 - 用户: {}, 模型: {}", request.getUserId(), request.getModel());
        
        try {
            CompletableFuture<AiChatResponse> future = aiChatService.chatAsync(request);
            return R.ok(future);
        } catch (Exception e) {
            log.error("AI异步聊天启动失败", e);
            return R.fail("AI异步聊天启动失败: " + e.getMessage());
        }
    }

    /**
     * 流式聊天对话 (SSE)
     *
     * @param request 聊天请求
     * @return SSE流
     */
    @PostMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @Log(title = "AI流式聊天", businessType = BusinessType.OTHER)
    public SseEmitter chatStream(@Validated @RequestBody AiChatRequest request) {
        log.info("接收到AI流式聊天请求 - 用户: {}, 模型: {}", request.getUserId(), request.getModel());
        
        SseEmitter emitter = new SseEmitter(TimeUnit.MINUTES.toMillis(10)); // 10分钟超时
        
        try {
            aiChatService.chatStream(request, new AiChatService.StreamCallback() {
                @Override
                public void onChunk(String chunk) {
                    try {
                        emitter.send(SseEmitter.event()
                            .name("chunk")
                            .data(chunk));
                    } catch (IOException e) {
                        log.error("发送SSE数据块失败", e);
                        emitter.completeWithError(e);
                    }
                }
                
                @Override
                public void onComplete(AiChatResponse response) {
                    try {
                        emitter.send(SseEmitter.event()
                            .name("complete")
                            .data(response));
                        emitter.complete();
                    } catch (IOException e) {
                        log.error("发送SSE完成事件失败", e);
                        emitter.completeWithError(e);
                    }
                }
                
                @Override
                public void onError(Throwable error) {
                    log.error("AI流式聊天失败", error);
                    try {
                        emitter.send(SseEmitter.event()
                            .name("error")
                            .data("AI流式聊天失败: " + error.getMessage()));
                    } catch (IOException e) {
                        log.error("发送SSE错误事件失败", e);
                    }
                    emitter.completeWithError(error);
                }
            });
            
        } catch (Exception e) {
            log.error("AI流式聊天启动失败", e);
            emitter.completeWithError(e);
        }
        
        return emitter;
    }

    /**
     * 流式聊天对话 (WebSocket风格的分块响应)
     *
     * @param request 聊天请求
     * @param response HTTP响应
     */
    @PostMapping("/stream-chunks")
    @Log(title = "AI流式聊天分块", businessType = BusinessType.OTHER)
    public void chatStreamChunks(@Validated @RequestBody AiChatRequest request, 
                                HttpServletResponse response) {
        log.info("接收到AI流式聊天分块请求 - 用户: {}, 模型: {}", request.getUserId(), request.getModel());
        
        response.setContentType("text/plain; charset=utf-8");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Connection", "keep-alive");
        
        try {
            aiChatService.chatStream(request, new AiChatService.StreamCallback() {
                @Override
                public void onChunk(String chunk) {
                    try {
                        response.getWriter().write(chunk);
                        response.getWriter().flush();
                    } catch (IOException e) {
                        log.error("写入响应块失败", e);
                    }
                }
                
                @Override
                public void onComplete(AiChatResponse chatResponse) {
                    try {
                        response.getWriter().write("\n[DONE]\n");
                        response.getWriter().flush();
                        response.getWriter().close();
                    } catch (IOException e) {
                        log.error("完成响应写入失败", e);
                    }
                }
                
                @Override
                public void onError(Throwable error) {
                    try {
                        response.getWriter().write("\n[ERROR]: " + error.getMessage() + "\n");
                        response.getWriter().flush();
                        response.getWriter().close();
                    } catch (IOException e) {
                        log.error("写入错误响应失败", e);
                    }
                }
            });
            
        } catch (Exception e) {
            log.error("AI流式聊天分块启动失败", e);
            try {
                response.getWriter().write("\n[ERROR]: " + e.getMessage() + "\n");
                response.getWriter().flush();
                response.getWriter().close();
            } catch (IOException ioException) {
                log.error("写入启动错误响应失败", ioException);
            }
        }
    }

    /**
     * 批量聊天对话
     *
     * @param requests 聊天请求列表
     * @return 批量聊天响应
     */
    @PostMapping("/batch")
    @Log(title = "AI批量聊天", businessType = BusinessType.OTHER)
    public R<List<AiChatResponse>> chatBatch(@Validated @RequestBody List<AiChatRequest> requests) {
        log.info("接收到AI批量聊天请求 - 请求数量: {}", requests.size());
        
        try {
            List<CompletableFuture<AiChatResponse>> futures = aiChatService.chatBatch(requests);
            List<AiChatResponse> responses = aiChatService.waitForBatchCompletion(futures);
            return R.ok(responses);
        } catch (Exception e) {
            log.error("AI批量聊天失败", e);
            return R.fail("AI批量聊天失败: " + e.getMessage());
        }
    }

    /**
     * 获取聊天历史
     *
     * @param sessionId 会话ID
     * @param limit 限制数量
     * @return 聊天历史
     */
    @GetMapping("/history/{sessionId}")
    public R<List<AiChatRequest.AiMessage>> getChatHistory(
            @PathVariable String sessionId,
            @RequestParam(defaultValue = "50") Integer limit) {
        log.info("获取聊天历史 - 会话: {}, 限制: {}", sessionId, limit);
        
        try {
            // TODO: 实现聊天历史存储和检索
            return R.ok(List.of());
        } catch (Exception e) {
            log.error("获取聊天历史失败", e);
            return R.fail("获取聊天历史失败: " + e.getMessage());
        }
    }

    /**
     * 清除聊天历史
     *
     * @param sessionId 会话ID
     * @return 操作结果
     */
    @DeleteMapping("/history/{sessionId}")
    @Log(title = "清除聊天历史", businessType = BusinessType.DELETE)
    public R<Void> clearChatHistory(@PathVariable String sessionId) {
        log.info("清除聊天历史 - 会话: {}", sessionId);
        
        try {
            // TODO: 实现聊天历史清除
            return R.ok();
        } catch (Exception e) {
            log.error("清除聊天历史失败", e);
            return R.fail("清除聊天历史失败: " + e.getMessage());
        }
    }

    /**
     * 获取会话统计信息
     *
     * @param sessionId 会话ID
     * @return 统计信息
     */
    @GetMapping("/stats/{sessionId}")
    public R<Object> getSessionStats(@PathVariable String sessionId) {
        log.info("获取会话统计 - 会话: {}", sessionId);
        
        try {
            // TODO: 实现会话统计
            return R.ok(new Object());
        } catch (Exception e) {
            log.error("获取会话统计失败", e);
            return R.fail("获取会话统计失败: " + e.getMessage());
        }
    }
}